import { describe, it, expect, vi } from 'vitest'
import fc from 'fast-check'
import { retryWithBackoff } from './retry.js'
import { APIError } from '../middleware/error.js'

describe('Retry Logic', () => {
  // **Feature: emotion-3d-website, Property 12: Rate Limit Retry Logic**
  // **Validates: Requirements 6.4**
  it('should retry with exponential backoff for rate limit errors', async () => {
    await fc.assert(
      fc.asyncProperty(
        fc.integer({ min: 1, max: 3 }),
        async (maxAttempts: number) => {
          let attemptCount = 0
          const mockFn = vi.fn(async () => {
            attemptCount++
            if (attemptCount < maxAttempts) {
              throw new APIError('Rate limit exceeded', 429, true)
            }
            return 'success'
          })

          try {
            // Use initialDelay of 0 to speed up test
            const result = await retryWithBackoff(mockFn, { maxAttempts, initialDelay: 0 })
            
            // Should eventually succeed
            expect(result).toBe('success')
            // Should have retried the correct number of times
            expect(attemptCount).toBe(maxAttempts)
            
            return true
          } catch (error) {
            // If it fails, it should be after max attempts
            return attemptCount === maxAttempts
          }
        }
      ),
      { numRuns: 10 }
    )
  })

  it('should not retry non-retryable errors', async () => {
    const mockFn = vi.fn(async () => {
      throw new APIError('Bad request', 400, false)
    })

    try {
      await retryWithBackoff(mockFn, { maxAttempts: 3 })
      expect.fail('Should have thrown error')
    } catch (error) {
      // Should only attempt once for non-retryable errors
      expect(mockFn).toHaveBeenCalledTimes(1)
      expect(error).toBeInstanceOf(APIError)
    }
  })
})
